import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError } from 'rxjs/operators';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';

import { HttpAssist } from '../assist/http-assist';
import { HttpOperations } from '../http/http-operations';
import { StringMap } from '../type/map-type';
import { HttpOptionsT } from '../type/http-type';
import { ErrorRs } from '../../modules/error-rs';

@Injectable()
export class HttpService {

  constructor(private http: HttpClient) { }

  /**
   * GET Method
   */
  public getByJson<T> (serviceName: string, serviceType: string, params?: HttpParams): Observable<any | T> {
    return this.http
      .get<T>(HttpOperations.hostfullurl, this.options(HttpAssist.CONTENT_TYPE_JSON, serviceName,serviceType, params))
      .pipe(
        catchError(this.handleError('Request data to webservice by GET method failed.'))
      );
  }

  /**
   * Post Method (form)
   */
  public formByJson<T> (serviceName: string, serviceType: string, params?: HttpParams): Observable<any | T> {
    return this.http
      .post<T>(HttpOperations.hostfullurl, null, this.options(HttpAssist.CONTENT_TYPE_JSON, serviceName,serviceType, params))
      .pipe(
        catchError(this.handleError('Request data to webservice by POST (form) method failed.'))
      );
  }

  /**
   * Post Method (form)
   */
  public form (serviceName: string, serviceType: string, params?: HttpParams): Observable<Object> {
    return this.http
      .post(HttpOperations.hostfullurl, null, this.options(HttpAssist.CONTENT_TYPE_JSON, serviceName,serviceType, params));
  }

  /**
   * Post Method
   */
  public postByJson<T> (serviceName: string, serviceType: string, body: any): Observable<any | T> {
    return this.http
      .post<T>(HttpOperations.hostfullurl, body, this.options(HttpAssist.CONTENT_TYPE_JSON, serviceName,serviceType))
      .pipe(
        catchError(this.handleError('Request data to webservice by POST method failed.'))
      );
  }

  public options(contentType: string, serviceName?: string, serviceType?: string, params?: HttpParams) {
    const httpOtions = new HttpOptionsT();

    const headerOpts = this.headers(contentType, serviceName,serviceType);
    if (headerOpts) {
      httpOtions.headers = headerOpts;
    }

    if (params) {
      httpOtions.params = params;
    }

    return httpOtions;
  }

  private headers(contentType: string, serviceName?: string, serviceType?: string): HttpHeaders {
    let setFlag = false;

    const headerMap = new StringMap();
    if (HttpAssist.CONTENT_TYPE_JSON === contentType) {
      setFlag = true;
      headerMap[HttpAssist.CONTENT_TYPE_NAME] = HttpAssist.CONTENT_TYPE_JSON;
    }

    if (serviceName) {
      setFlag = true;
      headerMap[HttpAssist.SERVICE_NAME] = serviceName;
    }
    
    if (serviceType) {
      setFlag = true;
      headerMap[HttpAssist.SERVICE_TYPE] = serviceType;
    }

    const headerOpts: HttpHeaders = new HttpHeaders(headerMap);

    return setFlag ? headerOpts : null;
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  private handleError (operation = 'operation') {
    return (error: any): Observable<ErrorRs> => {
      // send the error to remote logging infrastructure
      console.error(operation); // log to console instead

      const rs = new ErrorRs();
      rs.statusCode = error.status;
      rs.message = 'System Exception Occured.';

      return new ErrorObservable(rs);
    };
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  public handleErrorExtend (error: any, operation = 'operation'): ErrorRs  {
    // send the error to remote logging infrastructure
    console.error(operation); // log to console instead

    const rs = new ErrorRs();
    rs.statusCode = error.status;
    rs.message = 'System Exception Occured.';
    return rs;
  }
}
